﻿/* 环形队列
 */

namespace LSLib.Collections
{
    using System;
    using System.Collections.Generic;

    public interface IBuffer<T>
    {
        int Length { get; }
        T this[int index] { get; set; }
    }

    public class CircleQueue : CircleQueue<byte>
    {
        public CircleQueue()
        { }
        public CircleQueue(int length)
            : base(length)
        { }
        public CircleQueue(IList<byte[]> buffer)
            : base(buffer)
        { }
        protected CircleQueue(IBuffer<byte> buffer)
            : base(buffer)
        { }
    }

    public class CircleQueue<T>
    {
        #region 字段
        private IBuffer<T> m_Buffer;
        private const int DefaultLength = 1024;
        private int m_Count = 0;
        private int m_PositionWrite = 0;
        private int m_PositionRead = 0;
        private static readonly object syncRoot = new object();
        #endregion

        #region 属性
        public int Length
        {
            get { return m_Buffer.Length; }
        }

        public int Count
        {
            get
            {
                lock (syncRoot)
                {
                    return m_Count;
                }
            }
            private set
            {
                if (value < 0 || value > this.Length) throw new Exception();
                this.m_Count = value;
            }
        }

        public int PositionWrite
        {
            get { return m_PositionWrite; }
            private set
            {
                if (value < 0) throw new Exception();
                if (value > this.Length - 1) value -= this.Length;
                this.m_PositionWrite = value;
            }
        }

        public int PositionRead
        {
            get { return m_PositionRead; }
            private set
            {
                if (value < 0) throw new Exception();
                if (value > this.Length - 1) value -= this.Length;
                this.m_PositionRead = value;
            }
        }
        #endregion

        #region 构造函数
        public CircleQueue()
            : this(DefaultLength)
        { }
        public CircleQueue(int length)
            : this(new ArrayBuffer<T>(new T[length]))
        { }
        public CircleQueue(IList<T[]> buffer)
            : this(new MultiBuffer<T>(buffer))
        { }
        protected CircleQueue(IBuffer<T> buffer)
        {
            m_Buffer = buffer;
        }
        #endregion

        #region 公共函数
        public void Write(T[] data)
        {
            int dataLength = data.Length;
            if (dataLength > this.GetCanWriteSpace()) throw new ArgumentException();

            lock (syncRoot)
            {
                for (int i = 0; i < dataLength; i++)
                {
                    this.m_Buffer[this.PositionWrite] = data[i];
                    this.PositionWrite++;
                }
                this.Count += dataLength;
            }
        }

        public T[] Read(int readLength)
        {
            if (readLength > this.GetCanReadSpace()) throw new ArgumentException();

            T[] result = new T[readLength];
            lock (syncRoot)
            {
                for (int i = 0; i < readLength; i++)
                {
                    result[i] = this.m_Buffer[this.PositionRead];
                    this.PositionRead++;
                }
                this.Count -= readLength;
            }
            return result;
        }

        public int GetCanWriteSpace()
        {
            return (this.Length - this.Count);
        }

        public int GetCanReadSpace()
        {
            return this.Count;
        }
        #endregion

        private class ArrayBuffer<TAbuf> : IBuffer<TAbuf>
        {
            private TAbuf[] m_Buffer;
            public ArrayBuffer(TAbuf[] buf)
            {
                m_Buffer = buf;
            }

            public int Length
            {
                get { return m_Buffer.Length; }
            }

            public TAbuf this[int index]
            {
                get
                {
                    return m_Buffer[index];
                }
                set
                {
                    m_Buffer[index] = value;
                }
            }
        }

        private class MultiBuffer<TMbuf> : IBuffer<TMbuf>
        {
            private int m_Length = 0;
            private IList<TMbuf[]> m_List;
            private SortedList<Range, RangeValue> m_RangeList;

            public MultiBuffer(IList<TMbuf[]> list)
            {
                m_List = list;

                #region InitLength
                if (m_List != null)
                {
                    foreach (TMbuf[] buf in m_List)
                    {
                        m_Length += buf.Length;
                    }
                }
                #endregion

                #region InitDict
                RangeCompare rc = new RangeCompare();
                this.m_RangeList = new SortedList<Range, RangeValue>(rc);

                int index = 0;
                for (int i = 0; i < list.Count; i++)
                {
                    Range r = new Range(index, index + list[i].Length - 1);
                    RangeValue rv = new RangeValue(i, index);
                    this.m_RangeList.Add(r, rv);
                    index += list[i].Length;
                }
                #endregion
            }

            public int Length
            {
                get { return m_Length; }
            }

            public TMbuf this[int index]
            {
                get
                {
                    Range r = new Range(index, index);
                    RangeValue rv;
                    if (this.m_RangeList.TryGetValue(r, out rv))
                        return this.m_List[rv.ListIndex][index - rv.ArrayStartIndex];
                    else
                        throw new Exception(string.Format("找不到 index={0} 时对应的位置。", index));
                    #region MyRegion
                    //for (int i = 0; i < m_List.Count; i++)
                    //{
                    //    TMbuf[] buf = null;
                    //    buf = m_List[i];
                    //    if (index < m_List[i].Length)
                    //    {
                    //        return buf[index];
                    //    }
                    //    else
                    //    {
                    //        index -= buf.Length;
                    //    }
                    //}
                    //throw new ArgumentOutOfRangeException();
                    #endregion
                }
                set
                {
                    Range r = new Range(index, index);
                    RangeValue rv;
                    if (this.m_RangeList.TryGetValue(r, out rv))
                        this.m_List[rv.ListIndex][index - rv.ArrayStartIndex] = value;
                    else
                        throw new Exception(string.Format("找不到 index={0} 时对应的位置。", index));
                    #region MyRegion
                    //for (int i = 0; i < m_List.Count; i++)
                    //{
                    //    TMbuf[] buf = null;
                    //    buf = m_List[i];
                    //    if (index < m_List[i].Length)
                    //    {
                    //        buf[index] = value;
                    //        return;
                    //    }
                    //    else
                    //    {
                    //        index -= buf.Length;
                    //    }
                    //}
                    //throw new ArgumentOutOfRangeException();
                    #endregion
                }
            }
        }

        struct Range
        {
            public int StartIndex;
            public int EndIndex;

            public Range(int startIndex, int endIndex)
            {
                this.StartIndex = startIndex;
                this.EndIndex = endIndex;
            }
        }
        struct RangeValue
        {
            public int ListIndex;//该数组在列表中的索引
            public int ArrayStartIndex;//该数组项开始的索引

            public RangeValue(int listIndex, int arrayStartIndex)
            {
                this.ListIndex = listIndex;
                this.ArrayStartIndex = arrayStartIndex;
            }
        }

        private class RangeCompare : IComparer<Range>
        {
            public int Compare(Range x, Range y)
            {
                if ((y.StartIndex < x.StartIndex) && (y.EndIndex < x.StartIndex))
                    return -1;
                else if ((y.StartIndex >= x.StartIndex) && (y.EndIndex <= x.EndIndex))
                    return 0;
                else if ((y.StartIndex > x.EndIndex) && (y.EndIndex > x.EndIndex))
                    return 1;
                else
                    return -1;
            }
        }
    }
}